// check integer
owl_byte owl_check_wchar_utf8(owl_wchar ch)
{
  // check params
  if (owl_check_wchar_unicode(ch) == 0)
    return 0;
  
  // return the size
  if (ch < OWL_MAX_UTF8_CHAR_1BYTE + 1)
    return 1;
  else if (ch < OWL_MAX_UTF8_CHAR_2BYTE + 1)
    return 2;
  else if (ch < OWL_MAX_UTF8_CHAR_3BYTE + 1)
    return 3;
  /* ch < OWL_MAX_UTF8_CHAR_4BYTE + 1 */
  return 4;
}

// check encoded
owl_byte owl_check_wchar_enc_utf8(owl_byte * src, owl_umax size)
{
  // check params
  owl_byte ch_size = 0;
  if (owl_check_ptr(src, size) == owl_false )
    goto end;
 
  // check the starting bits of each byte of src
  // while checking if the characters can be read
  if ((OWL_UTF8_MASK_1 & src[0]) == 0) // 1 byte
    ch_size = 1;
  else if (size >= 2 
           && (OWL_UTF8_MASK_3 & src[0]) == OWL_UTF8_MASK_2
           && (OWL_UTF8_MASK_2 & src[1]) == OWL_UTF8_MASK_1) // 2 bytes
    ch_size = 2;
  else if (size >= 3
           && (OWL_UTF8_MASK_4 & src[0]) == OWL_UTF8_MASK_3
           && (OWL_UTF8_MASK_2 & src[1]) == OWL_UTF8_MASK_1
           && (OWL_UTF8_MASK_2 & src[2]) == OWL_UTF8_MASK_1) // 3 bytes
    ch_size = 3;
  else if (size >= 4
           && (OWL_UTF8_MASK_5 & src[0]) == OWL_UTF8_MASK_4
           && (OWL_UTF8_MASK_2 & src[1]) == OWL_UTF8_MASK_1
           && (OWL_UTF8_MASK_2 & src[2]) == OWL_UTF8_MASK_1
           && (OWL_UTF8_MASK_2 & src[3]) == OWL_UTF8_MASK_1) // 4 bytes
    ch_size = 4;
  // return
  end:
  return ch_size;
}

// get integer
owl_wchar owl_get_wchar_utf8(owl_byte * src, owl_umax size)
{
  // check params
  owl_byte ch_size = owl_check_wchar_enc_utf8(src, size);
  if (ch_size == 0)
    return OWL_INV_UNICODE;
  
  // decode the character (EZPC)
  owl_wchar rtn = 0;
  if (ch_size == 1)
    rtn = (owl_wchar) *src;
  else if (ch_size == 2)
    rtn = (owl_wchar) ((~OWL_UTF8_MASK_3 & src[0]) << 6)
                       + (~OWL_UTF8_MASK_2 & src[1]);
  else if (ch_size == 3)
    rtn = (owl_wchar) ((~OWL_UTF8_MASK_4 & src[0]) << 12)
                       + ((~OWL_UTF8_MASK_2 & src[1]) << 6)
                       + (~OWL_UTF8_MASK_2 & src[2]);
  else /* ch_size == 4 */
    rtn = (owl_wchar) ((~OWL_UTF8_MASK_5 & src[0]) << 18)
                       + ((~OWL_UTF8_MASK_2 & src[1]) << 12)
                       + ((~OWL_UTF8_MASK_2 & src[2]) << 6)
                       + (~OWL_UTF8_MASK_2 & src[3]);
  return rtn;
}

// write encoded
owl_byte * owl_write_wchar_enc_utf8(owl_wchar ch, owl_byte * dest, owl_umax size)
{
  // check params
  owl_byte ch_size = owl_check_wchar_utf8(ch);
  if (ch_size == 0 || owl_check_ptr(dest, size) == owl_false || ch_size > size)
    return NULL;
  
  // encode the character (EZPC)
  if (ch_size == 1)
    *dest = (owl_byte) ch;
  else if (ch_size == 2) {
    dest[1] = (ch & ~OWL_UTF8_MASK_2) + OWL_UTF8_MASK_1;
    dest[0] = ((ch >> 6) & ~OWL_UTF8_MASK_3) + OWL_UTF8_MASK_2;
  } else if (ch_size == 3) {
    dest[2] = (ch & ~OWL_UTF8_MASK_2) + OWL_UTF8_MASK_1;
    dest[1] = ((ch >> 6) & ~OWL_UTF8_MASK_2) + OWL_UTF8_MASK_1;
    dest[0] = ((ch >> 12) & ~OWL_UTF8_MASK_4) + OWL_UTF8_MASK_3;
  } else /* ch_size == 4 */ {
    dest[3] = (ch & ~OWL_UTF8_MASK_2) + OWL_UTF8_MASK_1;
    dest[2] = ((ch >> 6) & ~OWL_UTF8_MASK_2) + OWL_UTF8_MASK_1;
    dest[1] = ((ch >> 12) & ~OWL_UTF8_MASK_2) + OWL_UTF8_MASK_1;
    dest[0] = ((ch >> 18) & ~OWL_UTF8_MASK_5) + OWL_UTF8_MASK_4;
  }
  
  // return the last write position
  return dest + ch_size;
}

// print integer
owl_byte owl_print_wchar_utf8(owl_wchar ch)
{
  if (owl_print_wchar_unicode(ch) == 0)
    return 0;
  return owl_check_wchar_utf8(ch);
}

// print encoded
owl_byte owl_print_wchar_enc_utf8(owl_byte * src, owl_umax size)
{
  // check params
  owl_wchar ch = owl_get_wchar_utf8(src, size);
  if (ch == OWL_INV_UNICODE) {
    printf(OWL_INV_ENC_UFT8_STR);
    return 0;
  }
  return owl_print_wchar_utf8(ch);
}

// bruh
owl_wchar owl_wchar_utf8_as_unicode(owl_wchar utf8)
{
  if (owl_check_wchar_utf8(utf8) == 0)
    return OWL_INV_UNICODE;
  return utf8;
}

// hurb
owl_wchar owl_wchar_unicode_as_utf8(owl_wchar unicode)
{
  return owl_wchar_utf8_as_unicode(unicode);
}
